﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ZebraDatePickerDotNet
{
    public enum ZebraDatePickerMode
    {
        Days,
        Months,
        Years
    }

    /// <summary>
    /// http://stefangabos.ro/jquery/zebra-datepicker/
    /// </summary>
    [ToolboxData(@"<{0}:ZDatePicker runat=""server"" \>")]
    public class ZDatePicker : TextBox
    {
        [Category("ZebraDatePicker"), DefaultValue("Days"), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Specify default calendar to use in datepikcer object")]
        public string Calendar
        {
            get { return (string)(ViewState["Calendar"] ?? ""); }
            set { ViewState["Calendar"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(true), Bindable(true), Localizable(false), Themeable(true)]
        [Description("By default, the button for clearing a previously selected date is shown only if a previously selected date already exists; this means that if the input the date picker is attached to is empty, and the user selects a date for the first time, this button will not be visible; once the user picked a date and opens the date picker again, this time the button will be visible.")]
        public bool AlwaysShowClear
        {
            get { return (bool)(ViewState["AlwaysShowClear"] ?? true); }
            set { ViewState["AlwaysShowClear"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(false), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Should the date picker be always visible? Setting this property to a jQuery element will result in the date picker being always visible, the indicated element acting as the date picker’s container; Note that when this property is set to TRUE, the “always_show_clear” property will be automatically set to TRUE.")]
        public bool AlwaysVisible
        {
            get { return (bool)(ViewState["AlwaysVisible"] ?? false); }
            set { ViewState["AlwaysVisible"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue("['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']"), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Days of the week. Sunday to Saturday.")]
        public string Days
        {
            get { return (string)(ViewState["Days"] ?? ""); }
            set { ViewState["Days"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Abbreviated names of days. By default, the abbreviated name of a day consists of the first 2 letters from the day’s full name. While this is common for most languages, there are also exceptions for languages like Thai, Loa, Myanmar, etc. where this is not correct. For these cases, specify an array with the abbreviations to be used for the 7 days of the week; leave it FALSE to use the first 2 letters of a day’s name as the abbreviation.")]
        public string DaysAbbr
        {
            get { return (string)(ViewState["DaysAbbr"] ?? string.Empty); }
            set { ViewState["DaysAbbr"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Direction of the calendar. A positive or negative integer: n (a positive integer) creates a future-only calendar beginning at n days after today; -n (a negative integer) creates a past-only calendar ending n days before today; if n is 0, the calendar has no restrictions. use boolean true for a future-only calendar starting with today and use boolean false for a past-only calendar ending today.")]
        public string Direction
        {
            get { return (string)(ViewState["Direction"] ?? string.Empty); }
            set { ViewState["Direction"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(false), Themeable(true)]
        [Description("An array of disabled dates in the following format: ‘day month year weekday’ where “weekday” is optional and can be 0-6 (Saturday to Sunday); The syntax is similar to cron’s syntax: the values are separated by spaces and may contain * (asterisk) – (dash) and , (comma) ")]
        public string DisabledDates
        {
            get { return (string)(ViewState["DisabledDates"] ?? string.Empty); }
            set { ViewState["DisabledDates"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(false), Themeable(true)]
        [Description("n array of enabled dates in the same format as required for “disabled_dates” property. To be used together with the “disabled_dates” property by first setting the “disabled_dates” property to something like “[* * * *]” (which will disable everything) and the setting the “enabled_dates” property to, say, “[* * * 0,6]” to enable just weekends.")]
        public string EnabledDates
        {
            get { return (string)(ViewState["EnabledDates"] ?? string.Empty); }
            set { ViewState["EnabledDates"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue("1"), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Week’s starting day. Valid values are 0 to 6, Sunday to Saturday.")]
        public string FirstDayOfWeek
        {
            get { return (string)(ViewState["FirstDayOfWeek"] ?? ""); }
            set { ViewState["FirstDayOfWeek"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue("Y-m-d"), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Format of the returned date. Accepts the following characters for date formatting: d, D, j, l, N, w, S, F, m, M, n, Y, y borrowing syntax from (PHP’s date function).")]
        public string Format
        {
            get { return (string)(ViewState["Format"] ?? ""); }
            set { ViewState["Format"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(false), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Should the icon for opening the datepicker be inside the element?  If set to FALSE, the icon will be placed to the right of the parent element, while if set to TRUE it will be placed to the right of the parent element, but *inside* the element itself")]
        public bool Inside
        {
            get { return (bool)(ViewState["Inside"] ?? true); }
            set { ViewState["Inside"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue("Clear"), Bindable(true), Localizable(true), Themeable(true)]
        [Description("the caption for the “Clear” button.")]
        public string LangClearDate
        {
            get { return (string)(ViewState["LangClearDate"] ?? ""); }
            set { ViewState["LangClearDate"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue("['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']"), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Months names. ")]
        public string Months
        {
            get { return (string)(ViewState["Months"] ?? ""); }
            set { ViewState["Months"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Abbreviated names of months. By default, the abbreviated name of a month consists of the first 3 letters from the month’s full name. While this is common for most languages, there are also exceptions for languages like Thai, Loa, Myanmar, etc. where this is not correct. For these cases, specify an array with the abbreviations to be used for the months of the year; leave it FALSE to use the first 3 letters of a month’s name as the abbreviation.")]
        public string MonthsAbbr
        {
            get { return (string)(ViewState["MonthsAbbr"] ?? ""); }
            set { ViewState["MonthsAbbr"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue("[5, -5]"), Bindable(true), Localizable(false), Themeable(true)]
        [Description("The offset, in pixels (x, y), to shift the date picker’s position relative to the top-right of the icon that toggles the date picker or, if the icon is disabled, relative to the top-right corner of the element the plugin is attached to.")]
        public string Offset
        {
            get { return (string)(ViewState["Offset"] ?? ""); }
            set { ViewState["Offset"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(true), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Should the element the calendar is attached to, be read-only? If set to TRUE, a date can be set only through the date picker and cannot be entered manually.")]
        public bool ReadonlyElement
        {
            get { return (bool)(ViewState["ReadonlyElement"] ?? true); }
            set { ViewState["ReadonlyElement"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(true), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Should days from previous and/or next month be selectable when visible? Note that if the value of this property is set to TRUE, the value of “show_other_months” will be considered TRUE regardless of the actual value!")]
        public bool SelectOtherMonths
        {
            get { return (bool)(ViewState["SelectOtherMonths"] ?? true); }
            set { ViewState["SelectOtherMonths"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(true), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Should a calendar icon be added to the elements the plugin is attached to? When set to TRUE the plugin will attach a calendar icon to the elements the plugin is attached to.")]
        public bool ShowIcon
        {
            get { return (bool)(ViewState["ShowIcon"] ?? true); }
            set { ViewState["ShowIcon"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(true), Bindable(true), Localizable(false), Themeable(true)]
        [Description("should days from previous and/or next month be visible?")]
        public bool ShowOtherMonths
        {
            get { return (bool)(ViewState["ShowOtherMonths"] ?? true); }
            set { ViewState["ShowOtherMonths"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(false), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Should day numbers < 10 be padded with zero? When set to TRUE, day numbers < 10 will be prefixed with 0.")]
        public bool ZeroPad
        {
            get { return (bool)(ViewState["ZeroPad"] ?? false); }
            set { ViewState["ZeroPad"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(false), Themeable(true)]
        [Description("Should an extra column be shown, showing the number of each week? Anything other than FALSE will enable this feature, and use the given value as column title. For example, show_week_number: ‘Wk’ would enable this feature and have “Wk” as the column’s title.")]
        public string ShowWeekNumber
        {
            get { return (string)(ViewState["ShowWeekNumber"] ?? ""); }
            set { ViewState["ShowWeekNumber"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(false), Themeable(true)]
        [Description("A default date to start the date picker with Must be specified in the format defined by the “format” property, or it will be ignored! Note that this value is used only if there is no value in the field the date picker is attached to!")]
        public string StartDate
        {
            get { return (string)(ViewState["StartDate"] ?? ""); }
            set { ViewState["StartDate"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(ZebraDatePickerMode.Days), Bindable(true), Localizable(false), Themeable(true)]
        [Description("How should the date picker start: Valid values are “days”, “months” and “years”.")]
        public ZebraDatePickerMode View
        {
            get { return (ZebraDatePickerMode)(ViewState["View"] ?? ZebraDatePickerMode.Days); }
            set { ViewState["View"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue("[0,6]"), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Days of the week that are considered “weekend days” Valid values are 0 to 6, Sunday to Saturday.")]
        public string WeekendDays
        {
            get { return (string)(ViewState["WeekendDays"] ?? ""); }
            set { ViewState["WeekendDays"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(""), Bindable(true), Localizable(true), Themeable(true)]
        [Description("Default javascript configuration, all property if set override this configuration")]
        public string DefaultConfiguration
        {
            get { return (string)(ViewState["DefaultConfiguration"] ?? "{}"); }
            set { ViewState["DefaultConfiguration"] = value; }
        }

        [Category("ZebraDatePicker"), DefaultValue(false), Bindable(true), Localizable(false), Themeable(true)]
        [Description("if set true, datepicker will override default config property using extend method")]
        public bool OverrideDefaultConfig
        {
            get { return (bool)(ViewState["OverrideDefaultConfig"] ?? false); }
            set { ViewState["OverrideDefaultConfig"] = value; }
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            Page.ClientScript.RegisterClientScriptResource(typeof(ZDatePicker), "ZebraDatePickerDotNet.ScriptBase.js");
        }

        protected override void Render(HtmlTextWriter writer)
        {
            string allConfig;
            if (!OverrideDefaultConfig)
            {
                allConfig = DefaultConfiguration;
            }
            else
            {
                var config = new List<string>();
                config.Add("always_show_clear:" + AlwaysShowClear.ToString().ToLower());
                config.Add("always_visible:" + AlwaysVisible.ToString().ToLower());

                if (!string.IsNullOrEmpty(FirstDayOfWeek))
                    config.Add("first_day_of_week:" + FirstDayOfWeek);

                if (!string.IsNullOrEmpty(Days))
                    config.Add("days:" + Days);

                if (!string.IsNullOrEmpty(DaysAbbr))
                    config.Add("days_abbr:" + DaysAbbr);

                if (!string.IsNullOrEmpty(Direction))
                    config.Add("direction:" + Direction);

                if (!string.IsNullOrEmpty(DisabledDates))
                    config.Add("disabled_dates:" + DisabledDates);

                if (!string.IsNullOrEmpty(EnabledDates))
                    config.Add("enabled_dates:" + EnabledDates);

                if (!string.IsNullOrEmpty(Format))
                    config.Add("format:'" + Format + "'");

                config.Add("inside:" + Inside.ToString().ToLower());

                if (!string.IsNullOrEmpty(LangClearDate))
                    config.Add("lang_clear_date:'" + LangClearDate + "'");

                if (!string.IsNullOrEmpty(Months))
                    config.Add("months:" + Months);

                if (!string.IsNullOrEmpty(MonthsAbbr))
                    config.Add("months_abbr:" + MonthsAbbr);

                if (!string.IsNullOrEmpty(Offset))
                    config.Add("offset:" + Offset);

                config.Add("readonly_element:" + ReadonlyElement.ToString().ToLower());
                config.Add("select_other_months:" + SelectOtherMonths.ToString().ToLower());
                config.Add("show_icon:" + ShowIcon.ToString().ToLower());
                config.Add("show_other_months:" + ShowOtherMonths.ToString().ToLower());

                if (!string.IsNullOrEmpty(ShowWeekNumber))
                    config.Add("show_week_number:'" + ShowWeekNumber + "'");

                if (!string.IsNullOrEmpty(StartDate))
                    config.Add("start_date:'" + StartDate + "'");

                config.Add("view:'" + View.ToString().ToLower() + "'");

                if (!string.IsNullOrEmpty(WeekendDays))
                    config.Add("weekend_days:" + WeekendDays);

                if (!string.IsNullOrEmpty(Calendar))
                    config.Add("calendar:" + Calendar);

                config.Add("zero_pad:" + ZeroPad.ToString().ToLower());

                allConfig = string.Format("$.extend({0},{{{1}}} )", DefaultConfiguration, string.Join(",", config));
            }

            string pageScript = "$(function () { LoadZDatePicker(\"" + ClientID + "\"," + allConfig + "); });";
            if (ScriptManager.GetCurrent(Page) != null)
            {
                ScriptManager.RegisterStartupScript(Page, Page.GetType(), "ZebraDatePicker" + ClientID + "Load",
                                                    pageScript, true);
            }
            else
            {
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "ZebraDatePicker" + ClientID + "Load",
                                                        pageScript, true);
            }

            base.Render(writer);
        }
    }
}
